package com.qingsong.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SecureUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.qingsong.dto.*;
import com.qingsong.entity.Emp;
import com.qingsong.entity.EmpRole;
import com.qingsong.entity.Role;
import com.qingsong.exception.ServiceException;
import com.qingsong.mapper.DeptMapper;
import com.qingsong.mapper.EmpMapper;
import com.qingsong.mapper.PermissionMapper;
import com.qingsong.mapper.RoleMapper;
import com.qingsong.service.EmpService;
import com.qingsong.util.JwtUtil;
import com.qingsong.util.MinioUtil;
import com.qingsong.vo.LoginVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @author qingsong
 */
@Service
@CacheConfig(cacheNames = "emp")
public class EmpServiceImpl implements EmpService {

    @Autowired
    private EmpMapper empMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private DeptMapper deptMapper;

    @CacheEvict(allEntries = true)
    @Override
    public int insert(EmpInsertDTO empInsertDTO){
        Emp emp = BeanUtil.copyProperties(empInsertDTO, Emp.class);
        // 密码加密
        emp.setPassword(SecureUtil.md5(emp.getPassword()));
        // 设置默认值
        String idcard = emp.getIdcard();
        emp.setAvatar("default-avatar.png");
        emp.setGender(IdcardUtil.getGenderByIdCard(idcard));
        emp.setAge(IdcardUtil.getAgeByIdCard(idcard));
        emp.setProvince(IdcardUtil.getProvinceByIdCard(idcard));
        emp.setAddress("暂未添加详细住址");
        emp.setInfo("暂未添加详细介绍");
        emp.setDeleted(0);
        emp.setCreated(LocalDateTime.now());
        emp.setUpdated(LocalDateTime.now());
        int result = empMapper.insert(emp);
        if (result <= 0) {
            throw new ServiceException("DB添加失败");
        }
        return result;

    }

    @Cacheable(key = "#id", condition = "#id != null", unless = "#result == null")
    @Override
    public Emp selectById(Long id) {
        Emp result = empMapper.selectById(id);
        if(ObjectUtil.isEmpty(result)){
            throw new ServiceException("ID不存在!");
        }
        return result;
    }

    @CacheEvict(allEntries = true)
    @Override
    public int updateById(EmpUpdateDTO empUpdateDTO) {
        Emp emp = BeanUtil.copyProperties(empUpdateDTO, Emp.class);

        emp.setCreated(LocalDateTime.now());
        emp.setUpdated(LocalDateTime.now());
        // DB修改
        int result = empMapper.updateById(emp);
        if (result <= 0) {
            throw new ServiceException("DB修改失败");
        }
        return result;
    }

    @CacheEvict(allEntries = true)
    @Override
    public int logicDeleteById(Long id) {
        roleMapper.existsEmpId(id);
        // todo 查询该记录是否被引用
        int result = empMapper.logicDeleteById(id);
        if(result <= 0){
            throw new ServiceException("数据库逻辑删除失败!");
        }
        return result;
    }

    @CacheEvict(allEntries = true)
    @Override
    public int logicDeleteByIds(List<Long> ids) {
        //DB删除基本表数据
        roleMapper.existsEmpIds(ids);
        int result = empMapper.logicDeleteByIds(ids);
        if(result <= 0){
            throw new ServiceException("数据库批量逻辑删除失败!");
        }
        return result;
    }

    @Cacheable(key = "#root.methodName", unless = "#result == null ")
    @Override
    public List<Emp> list() {
        return empMapper.list();
    }

    @Cacheable(key = "#root.methodName + ':' + " + "#pageDTO.getPageNum() + ':' + " + "#pageDTO.getPageSize()", unless = "#result == null ")
    @Override
    public PageInfo<Emp> page(PageDTO pageDTO) {
        PageHelper.startPage(pageDTO.getPageNum(), pageDTO.getPageSize());
        return new PageInfo<>(empMapper.list());
    }

    @Override
    public LoginVO loginByAccount(LoginDTO dto) {
        String username = dto.getUsername();
        String password = SecureUtil.md5(dto.getPassword());
        Emp emp = empMapper.selectByAccount(username,password);
        if(ObjectUtil.isNull(emp)){
            throw new ServiceException("账号或密码异常!");
        }
        //生成token令牌
        String token = JwtUtil.build(emp.getId(), emp.getRealname(), emp.getAvatar());
        //重组VO实体类,token令牌+权限列表
        LoginVO loginVO = new LoginVO();
        loginVO.setToken(token);
        loginVO.setPermissions(permissionMapper.selectByEmpId(emp.getId()));
        loginVO.setEmp(emp);
        loginVO.setDeptName(deptMapper.selectByEmpFkDeptId(emp.getId()));
        return loginVO;
    }

    @Cacheable(key = "#root.methodName + ':' + " +
            "#dto.getRealname() + ':' + " +
            "#dto.getPageNum() + ':' + " +
            "#dto.getPageSize()", unless = "#result == null ")
    @Override
    public PageInfo<Emp> pageLikeTitle(EmpPageDTO dto) {
        //开启分页
        PageHelper.startPage(dto.getPageNum(),dto.getPageSize());
        //数据分页
        return new PageInfo<>(empMapper.listLikeTitle(dto.getRealname()));
    }


    @CacheEvict(allEntries = true)
    @Override
    public String uploadAvatar(EmpUploadDTO dto) {

        final String DIR = "avatar";
        final String BUCKET_NAME = "start";
        MultipartFile avatarFile = dto.getAvatarFile();
        Long id = dto.getId();

        //DB查询
        Emp emp = empMapper.selectById(id);
        if(ObjectUtil.isNull(emp)){
            throw new ServiceException("员工不存在");
        }
        //从MINIO中删除旧文件,默认头像不删除
        String oldAvatar = emp.getAvatar();
        if(!("defult-avatar.png".equals(oldAvatar))){
            MinioUtil.delete(oldAvatar, DIR, BUCKET_NAME);
        }
        // 将文件上传到MINIO中
        String newAvatar = MinioUtil.randomFilename(avatarFile);
        MinioUtil.upload(avatarFile, newAvatar, DIR, BUCKET_NAME);

        // DB修改
        emp.setAvatar(newAvatar);
        if (empMapper.updateById(emp) <= 0) {
            throw new ServiceException("DB修改失败");
        }
        return newAvatar;
    }

    @CacheEvict(allEntries = true)
    @Override
    public String resetPassword(Long id) {
        String newPassword = "123456789";
        Emp emp = new Emp();
        emp.setId(id);
        emp.setPassword(SecureUtil.md5(newPassword));
        emp.setUpdated(LocalDateTime.now());
        //DB修改
        if(empMapper.updateById(emp) <= 0){
            throw new ServiceException("密码重置失败");
        }
        return newPassword;
    }

    @Cacheable(key = "#root.methodName + ':' + #id", unless = "#result == null ")
    @Override
    public List<Role> getRoles(Long id) {
        return roleMapper.selectByEmpId(id);
    }

    @CacheEvict(allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateRoles(EmpUpdateRolesDTO dto) {
        Long id = dto.getId();
        List<Long> roleIds = dto.getRoleIds();
        for(Long roleId: roleIds){
            EmpRole empRole = new EmpRole();
            empRole.setFkRoleId(roleId);
            empRole.setFkEmpId(id);
            empRole.setDeleted(0);
            empRole.setCreated(LocalDateTime.now());
            empRole.setUpdated(LocalDateTime.now());
            if(roleMapper.insertEmpRole(empRole) <= 0){
                throw new ServiceException("添加角色失败");
            }
        }
        return 1;
    }

    @CacheEvict(allEntries = true)
    @Override
    public int updatePassword(EmpUpdatePasswordDTO dto) {
        String newPassword = SecureUtil.md5(dto.getNewPassword());
        String oldPassword = SecureUtil.md5(dto.getOldPassword());
        Long id = dto.getId();
        int result = empMapper.updatePassword(newPassword,oldPassword,id);
        if(result <= 0){
            throw new ServiceException("修改密码失败");
        }
        return result;
    }

}
